package com.sl.core.engine.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.sl.core.engine.datasource.AnylineServiceAdaptor;
import com.sl.core.engine.log.ProcessLoggingBuffer;
import com.sl.core.engine.log.store.LoggerStoreFactory;
import com.sl.core.engine.log.store.domain.entity.LogDetailDO;
import com.sl.core.engine.log.store.domain.entity.MainLogDO;
import com.sl.core.engine.trans.ProcessInstance;
import com.sl.core.engine.trans.ProcessTrans;
import com.sl.core.engine.utils.ZipUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.hop.core.exception.HopException;
import org.apache.hop.core.logging.HopLogStore;
import org.apache.hop.core.logging.LoggingBuffer;
import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.pipeline.engine.IPipelineEngine;

import java.util.Collections;
import java.util.Date;
import java.util.List;

@Slf4j
public class PipelineExecutionListener implements PipelineListener {

    public static PipelineExecutionListener INSTANCE = new PipelineExecutionListener();

    @Override
    public void finished(IPipelineEngine<PipelineMeta> engine) {
        if (!(engine instanceof ProcessTrans p)) {
            return;
        }
        int errors = p.getErrors();

        //提交事物
        AnylineServiceAdaptor anylineServiceAdaptor = p.getAnylineServiceAdaptor();
        if (ObjectUtil.isNotNull(anylineServiceAdaptor)) {
            if (errors > 0) {
                anylineServiceAdaptor.rollBack();
            } else {
                anylineServiceAdaptor.commit();
            }
            anylineServiceAdaptor.destroy();
        }
        //保存日志
        //建一条日志记录
        if (!(engine instanceof ProcessInstance ps)) {
            return;
        }
        finishMain(ps);
    }

    public void finishMain(ProcessInstance ps) {

        Boolean saveLogFlag = ps.getFinishEnduranceLogFlag();
        if (BooleanUtil.isTrue(saveLogFlag)) {
            return;
        }
        Boolean saveMainLogFlag = ps.getSaveMainLogFlag();

        Boolean childProcessFlag = ps.isChildProcessFlag();
        String logStoreTypeCode = ps.getLogStoreTypeCode();

        Integer state = ps.isEnd();

        //保存主表
        if (BooleanUtil.isFalse(childProcessFlag) && BooleanUtil.isTrue(saveMainLogFlag)) {

            LoggerStoreFactory.INSTANCE.finishMain(
                    ps.getTid(),
                    ps.getExecutionEndDate(),
                    state,
                    logStoreTypeCode
            );
        }

        saveDetail(ps);

        ps.setFinishEnduranceLogFlag(true);
    }

    public void saveDetail(ProcessInstance ps) {
        Boolean saveDetailLogFlag = ps.getSaveDetailLogFlag();
        Boolean logDetailZipFlag = ps.getLogDetailZipFlag();
        Boolean childProcessFlag = ps.isChildProcessFlag();
        String logStoreTypeCode = ps.getLogStoreTypeCode();
        saveDetail(ps.getTid(), ps.getInstanceId(), ps.getExecutionStartDate(), ps.getProcessName(),
                ps.getProcessId(), ps.getProcessVersion(), ps.getErrorText(), ps.getExecutionEndDate(),
                saveDetailLogFlag, logDetailZipFlag, childProcessFlag, logStoreTypeCode);
    }

    public void saveDetail(String tid, String instanceId, Date startDate,
                           String processName, String processId, String processVersion, String errorText,
                           Date endDate, Boolean saveDetailLogFlag, Boolean logDetailZipFlag,
                           Boolean childProcessFlag, String logStoreTypeCode) {
        List<String> features = getFeatures(tid, instanceId, logDetailZipFlag);
        if (CollUtil.isEmpty(features)) {
            features.add("");
        }
        if (BooleanUtil.isFalse(saveDetailLogFlag)) {
            return;
        }
        for (String feature : features) {
            LogDetailDO logDetailDO = buildLogDetail(tid, instanceId, startDate, endDate,
                    processName, processId, processVersion, errorText, feature, childProcessFlag);
            //保存子表
            LoggerStoreFactory.INSTANCE.saveDetail(logDetailDO, logStoreTypeCode);
        }
    }

    public LogDetailDO buildLogDetail(String tid, String instanceId, Date startDate, Date endDate,
                                      String processName, String processId, String processVersion,
                                      String errorText, String feature, Boolean childProcessFlag) {
        LogDetailDO logDetailDO = new LogDetailDO();
        logDetailDO.setTid(tid);
        logDetailDO.setInstanceId(instanceId);
        logDetailDO.setStartTime(startDate);
        logDetailDO.setProcessName(processName);
        logDetailDO.setProcessId(processId);
        logDetailDO.setProcessVersion(processVersion);
        logDetailDO.setFeature(feature);
        logDetailDO.setState(StrUtil.isNotBlank(errorText) ? 1 : 2);
        logDetailDO.setErrors(errorText);
        if (ObjectUtil.isAllNotEmpty(startDate, endDate)) {
            long cost = DateUtil.betweenMs(startDate, endDate);
            logDetailDO.setCost(cost);
        }
        logDetailDO.setEndTime(endDate);
        logDetailDO.setMainProcessFlag(BooleanUtil.isTrue(childProcessFlag) ? 0 : 1);
        return logDetailDO;
    }

    public List<String> getFeatures(String tid, String instanceId, Boolean logDetailZipFlag) {
        LoggingBuffer appender = HopLogStore.getAppender();
        if (!(appender instanceof ProcessLoggingBuffer buffer)) {
            return Collections.emptyList();
        }

        String concat = buffer.buildKey(tid, instanceId);
        String logText = buffer.pollAllByKey(concat);

        //对日志做压缩
        if (BooleanUtil.isTrue(logDetailZipFlag)) {
            logText = ZipUtil.zip(logText);
        }
        return Lists.newArrayList(logText);
    }

    @Override
    public void started(IPipelineEngine<PipelineMeta> engine) throws HopException {
        log.info("PipelineExecutionListener->started");

        //建一条日志记录
        if (!(engine instanceof ProcessInstance p)) {
            return;
        }
        Boolean childProcessFlag = p.isChildProcessFlag();
        String logStoreTypeCode = p.getLogStoreTypeCode();
        //保存主表
        if (BooleanUtil.isFalse(childProcessFlag)) {
            MainLogDO mainLogDO = buildMainLog(p);
            LoggerStoreFactory.INSTANCE.startMain(mainLogDO, logStoreTypeCode);
        }
//

    }

    public MainLogDO buildMainLog(ProcessInstance p) {
        MainLogDO mainLogDO = new MainLogDO();
        mainLogDO.setTid(p.getTid());
        mainLogDO.setStartTime(p.getExecutionStartDate());
        mainLogDO.setProcessName(p.getProcessName());
        mainLogDO.setProcessId(p.getProcessId());
        mainLogDO.setProcessVersion(p.getProcessVersion());
        mainLogDO.setCollectLogId(p.getCompensateLogId());
        return mainLogDO;
    }

}
